#include <stdio.h>  
#include <string.h>  
#include <stdint.h>  
#include <stdlib.h>  
#include "gmssl/rand.h"  
#include "gmssl/sm4.h"  

#define PLAINTEXT_LEN 130  

void print_hex(const char *title, const uint8_t *data, size_t len) {  
	    printf("%s:", title);  
	        for (size_t i = 0; i < len; i++) {  
			        if (i % 16 == 0) {  
					            printf("\n%04zx: ", i);  
						            }  
				        printf("%02X ", data[i]);  
					    }  
		    printf("\n");  
}  

int main() {  
	    int ret = 0;  
	        uint8_t key[SM4_KEY_SIZE];  
		    uint8_t iv[SM4_BLOCK_SIZE];  
		        uint8_t plaintext[PLAINTEXT_LEN];  
			    uint8_t ciphertext[PLAINTEXT_LEN + SM4_BLOCK_SIZE]; // 棰勭暀濉厖绌洪棿  
			        uint8_t decrypted[PLAINTEXT_LEN + SM4_BLOCK_SIZE];  
				    size_t outlen = 0;  
				        size_t total_outlen = 0;  

					    if (rand_bytes(key, sizeof(key)) != 1) {  
						            fprintf(stderr, "鐢熸垚闅忔満 Key 澶辫触\n");  
							            return 1;  
								        }  

					        if (rand_bytes(iv, sizeof(iv)) != 1) {  
							        fprintf(stderr, "鐢熸垚闅忔満 IV 澶辫触\n");  
								        return 1;  
									    }  

						    memset(plaintext, 'A', sizeof(plaintext)); // 鐢ㄥ瓧绗?'A' 濉厖  

						        plaintext[0] = 'H';  
							    plaintext[1] = 'e';  
							        plaintext[2] = 'l';  
								    plaintext[3] = 'l';  
								        plaintext[4] = 'o';  
									    plaintext[5] = ',';  
									        plaintext[6] = ' ';  
										    plaintext[7] = 'S';  
										        plaintext[8] = 'M';  
											    plaintext[9] = '4';  
											        plaintext[10] = '!';  
												   

												    printf("鍘熸枃锛圓SCII锛?\n%.*s\n\n", (int)PLAINTEXT_LEN, plaintext);  
												        print_hex("鍘熸枃锛堝崄鍏繘鍒讹級", plaintext, PLAINTEXT_LEN);  

													    SM4_CBC_CTX encrypt_ctx;  
													        ret = sm4_cbc_encrypt_init(&encrypt_ctx, key, iv);  
														    if (ret != 1) {  
															            fprintf(stderr, "sm4_cbc_encrypt_init 澶辫触\n");  
																            return 1;  
																	        }  

														        ret = sm4_cbc_encrypt_update(&encrypt_ctx, plaintext, PLAINTEXT_LEN, ciphertext, &outlen);  
															    if (ret != 1) {  
																            fprintf(stderr, "sm4_cbc_encrypt_update 澶辫触\n");  
																	            return 1;  
																		        }  
															        total_outlen += outlen;  

																    ret = sm4_cbc_encrypt_finish(&encrypt_ctx, ciphertext + total_outlen, &outlen);  
																        if (ret != 1) {  
																		        fprintf(stderr, "sm4_cbc_encrypt_finish 澶辫触\n");  
																			        return 1;  
																				    }  
																	    total_outlen += outlen;  

																	        printf("\n瀵嗘枃锛堝崄鍏繘鍒讹級锛?);  
																			    print_hex("瀵嗘枃", ciphertext, total_outlen);  

																		    SM4_CBC_CTX decrypt_ctx;  
																		        ret = sm4_cbc_decrypt_init(&decrypt_ctx, key, iv);  
																			    if (ret != 1) {  
																				            fprintf(stderr, "sm4_cbc_decrypt_init 澶辫触\n");  
																					            return 1;  
																						        }  

																			        size_t decrypted_len = 0;  
																				    ret = sm4_cbc_decrypt_update(&decrypt_ctx, ciphertext, total_outlen, decrypted, &outlen);  
																				        if (ret != 1) {  
																						        fprintf(stderr, "sm4_cbc_decrypt_update 澶辫触\n");  
																							        return 1;  
																								    }  
																					    decrypted_len += outlen;  

																					        ret = sm4_cbc_decrypt_finish(&decrypt_ctx, decrypted + decrypted_len, &outlen);  
																						    if (ret != 1) {  
																							            fprintf(stderr, "sm4_cbc_decrypt_finish 澶辫触\n");  
																								            return 1;  
																									        }  
																						        decrypted_len += outlen;  

																							    printf("\n瑙ｅ瘑鍚庣殑鏄庢枃锛圓SCII锛?\n%.*s\n\n", (int)decrypted_len, decrypted);  
																							        print_hex("瑙ｅ瘑鍚庣殑鏄庢枃锛堝崄鍏繘鍒讹級", decrypted, decrypted_len);  

																								    if (decrypted_len != PLAINTEXT_LEN || memcmp(plaintext, decrypted, PLAINTEXT_LEN) != 0) {  
																									            fprintf(stderr, "瑙ｅ瘑鍚庣殑鏄庢枃涓庡師鏂囦笉涓€鑷达紒\n");  
																										            return 1;  
																											        }  

																								        printf("\n瑙ｅ瘑鎴愬姛锛屾槑鏂囦笌鍘熸枃涓€鑷淬€俓n");  

																									    return 0;  
}
